package com.atguigu.tingshu.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.RechargeInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.account.RechargeInfo;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

	@Autowired
	private PaymentInfoService paymentInfoService;
    @Autowired
    private WxPayV3Config wxPayV3Config;
    @Autowired
    private RSAAutoCertificateConfig config;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private PaymentInfoService paymentInfoService
    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;
    @Autowired
    private RechargeInfoFeignClient rechargeInfoFeignClient;

    /**
     * 创建微信支付订单
     *
     * @param paymentType
     * @param orderNo
     * @param userId
     * @return
     */
    @Override
    public Map createJsapi(String paymentType, String orderNo, Long userId) {
        //创建Map集合
        Map<String, Object> result = new HashMap();
        //记录交易记录，方便后续对账！ payment_info
        //声明一个变量，存储交易记录  金额
        BigDecimal payAmount = new BigDecimal("0.00");
        //根据订单编号查询订单对象
        if (paymentType.equals(SystemConstant.PAYMENT_TYPE_ORDER)) { //PAYMENT_TYPE_ORDER="1301";  // 订单
            //order_info.order_amount 订单总价
            Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderNo);
            Assert.notNull(orderInfoResult.getData(), "订单不存在");
            OrderInfo orderInfo = orderInfoResult.getData();
            Assert.notNull(orderInfo, "订单不存在");
            //判断当前这个订单状态，如果这订单已取消了，则不能再次点击支付
            if (SystemConstant.ORDER_STATUS_CANCEL.equals(orderInfo.getOrderStatus())) {
                result.put("code","504");
                result.put("message","订单已取消");
                return result;
            }
            payAmount=orderInfo.getOrderAmount();

        }else { //PAYMENT_TYPE_RECHARGE="1302";  // 充值 tingshu_account
            //recharge_info充值信息recharge_amount充值金额
            Result<RechargeInfo> rechargeInfoResult = rechargeInfoFeignClient.getRechargeInfo(orderNo);
            Assert.notNull(rechargeInfoResult, "充值信息不存在");
            RechargeInfo rechargeInfo = rechargeInfoResult.getData();
            Assert.notNull(rechargeInfo, "充值信息不存在");
            payAmount=rechargeInfo.getRechargeAmount();

        }
        paymentInfoService.savePaymentInfo(userId,paymentType,orderNo,payAmount);

        //构建service对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();

        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(1); //单位 微信：分 支付宝：元  正常  amount.setTotal(payAmount);
        request.setAmount(amount);
        request.setAppid(wxPayV3Config.getAppid());
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setDescription("测试商品标题");
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        request.setOutTradeNo(orderNo);
        //request.setTimeExpire(); //设置过期时间 等于取消订单的时间

        //创建一个Plauer
        Payer payer = new Payer();

        //远程调用user服务，根据用户id获取该用户的openid
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
        Assert.notNull(userInfoVoResult.getData(), "用户信息不存在");
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        Assert.notNull(userInfoVo.getWxOpenId(), "用户openid不存在");

        //设置支付者的openid
        payer.setOpenid(userInfoVo.getWxOpenId());
        //设置支付者
        request.setPayer(payer);

        // response包含了调起支付所需的所有参数，可直接用于前端调起支付
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        //赋值必要属性
        result.put("timeStamp", response.getTimeStamp()); // 时间戳
        result.put("nonceStr", response.getNonceStr());   // 随机字符串
        result.put("package", response.getPackageVal());  // 订单详情扩展字符串
        result.put("signType", response.getSignType());   // 签名方式
        result.put("paySign", response.getPaySign());     // 签名
        return result;
    }

    /**
     * 查询支付状态
     * @param orderNo
     * @return
     */
    @Override
    public Transaction queryPayStatus(String orderNo) {
        //        QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
        QueryOrderByOutTradeNoRequest outTradeNoRequest = new QueryOrderByOutTradeNoRequest();
        outTradeNoRequest.setMchid(wxPayV3Config.getMerchantId());//商户号
        outTradeNoRequest.setOutTradeNo(orderNo);//商户订单号
        try {
            //  构建service 对象
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
            Transaction transaction = service.queryOrderByOutTradeNo(outTradeNoRequest);
            System.out.println(transaction.getTradeState());
            //  返回这个对象transaction
            return transaction;
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
        }
        return null;
    }

    /**
     * 微信支付异步通知
     * @param request
     */
    @Override
    public void wxnotify(HttpServletRequest request) {
        //1.回调通知的验签与解密
        //从request头信息获取参数
        //HTTP 头 Wechatpay-Signature 应答的微信支付签名。
        // HTTP 头 Wechatpay-Nonce 签名中的随机数。
        //HTTP 头 Wechatpay-Timestamp 签名中的时间戳。
        //HTTP 头 Wechatpay-Serial  微信支付平台证书的序列号，验签必须使用序列号对应的微信支付平台证书。
        //HTTP 头 Wechatpay-Signature-Type 签名类型。
        //HTTP 请求体 body。切记使用原始报文，不要用 JSON 对象序列化后的字符串，避免验签的 body 和原文不一致。
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");//微信支付平台证书的序列号，验签必须使用序列号对应的微信支付平台证书。
        String nonce = request.getHeader("Wechatpay-Nonce"); // 签名中的随机数。
        String timestamp = request.getHeader("Wechatpay-Timestamp"); //签名中的时间戳。
        String signature = request.getHeader("Wechatpay-Signature");//应答的微信支付签名。
        //HTTP 请求体 body。切记使用原始报文，不要用 JSON 对象序列化后的字符串，避免验签的 body 和原文不一致。
        // 调用工具类来获取请求体数据
        String requestBody = PayUtil.readData(request);

        //2.构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody)
                .build();

        //3.初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        //4.以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        log.info("成功解析：{}", JSON.toJSONString(transaction));
        if(null != transaction && transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
            // 5.处理支付业务
            paymentInfoService.updatePaymentStatus(transaction);
        }
    }

    /**
     * 创建支付二维码
     * @param paymentType
     * @param orderNo
     * @param userId
     * @return
     */
    @Override
    public Map<String, Object> createNative(String paymentType, String orderNo, Long userId) {
        try {
            //创建Map集合
            Map<String, Object> result = new HashMap();
            //声明一个变量，存储交易记录金额
            BigDecimal payAmount = new BigDecimal("0.00");
            //根据订单编号查询订单对象
            if (paymentType.equals(SystemConstant.PAYMENT_TYPE_ORDER)) { //PAYMENT_TYPE_ORDER="1301";  // 订单
                //order_info.order_amount 订单总价
                Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderNo);
                Assert.notNull(orderInfoResult.getData(), "订单不存在");
                OrderInfo orderInfo = orderInfoResult.getData();
                Assert.notNull(orderInfo, "订单不存在");
                //判断当前这个订单状态，如果这订单已取消了，则不能再次点击支付
                if (SystemConstant.ORDER_STATUS_CANCEL.equals(orderInfo.getOrderStatus())) {
                    result.put("code","504");
                    result.put("message","订单已取消");
                    return result;
                }
                payAmount=orderInfo.getOrderAmount();

            }else { //PAYMENT_TYPE_RECHARGE="1302";  // 充值 tingshu_account
                //recharge_info充值信息recharge_amount充值金额
                Result<RechargeInfo> rechargeInfoResult = rechargeInfoFeignClient.getRechargeInfo(orderNo);
                Assert.notNull(rechargeInfoResult, "充值信息不存在");
                RechargeInfo rechargeInfo = rechargeInfoResult.getData();
                Assert.notNull(rechargeInfo, "充值信息不存在");
                payAmount=rechargeInfo.getRechargeAmount();

            }

            //保存支付记录
            PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(userId,paymentType,orderNo,payAmount);

            // 构建service
            NativePayService service = new NativePayService.Builder().config(config).build();
            // request.setXxx(val)设置所需参数，具体参数可见Request定义
            com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest request = new com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest();
            com.wechat.pay.java.service.payments.nativepay.model.Amount amount = new com.wechat.pay.java.service.payments.nativepay.model.Amount();
            amount.setTotal(1);
            request.setAmount(amount);
            request.setAppid(wxPayV3Config.getAppid());
            request.setMchid(wxPayV3Config.getMerchantId());
            request.setDescription(paymentInfo.getContent());
            request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
            request.setOutTradeNo(paymentInfo.getOrderNo());

            // 调用下单方法，得到应答
            com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse response = service.prepay(request);
            // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
            System.out.println(response.getCodeUrl());

            result.put("codeUrl", response.getCodeUrl());
            return result;
        } catch (ServiceException e) {
            e.printStackTrace();
            throw new GuiguException( 201, e.getErrorMessage());
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            throw new GuiguException( 201, "订单号不存在");
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuiguException( 201, "微信下单异常");
        }
    }

    @Override
    public boolean refund(String orderNo) {
        //  创建退款对象
        RefundService refundService = new RefundService.Builder().config(config).build();
        //  创建退款请求对象
        CreateRequest createRequest = new CreateRequest();
        createRequest.setOutTradeNo(orderNo);
        createRequest.setOutRefundNo(orderNo);
        AmountReq amountReq = new AmountReq();
        amountReq.setRefund(1l);
        amountReq.setTotal(1l);
        amountReq.setCurrency("CNY");
        createRequest.setAmount(amountReq);
        Refund refund = refundService.create(createRequest);
        //  判断
        if (refund.getStatus().equals(Status.SUCCESS)){
            //  关闭交易记录
            this.paymentInfoService.closePayment(orderNo);
            //  修改订单状态.
            return true;
        }
        return false;
    }
}
